package com.winit.deploy.task.phpTask;

import com.winit.common.util.ConfigUtil;
import com.winit.common.util.Constants;
import com.winit.common.util.ShellRunUtil;
import com.winit.core.server.factory.LinuxJumpServerFactory;
import com.winit.core.task.Task;
import com.winit.deploy.bean.WinitPhpInfo;
import com.winit.deploy.server.WinitJumpServer;
import com.winit.deploy.server.WinitPhpServer;
import com.winit.project.core.bean.PackageTypeEnum;
import com.winit.project.core.branch.Project;
import com.winit.project.core.set.ProjectSetConfig;
import com.winit.project.util.ProjectUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

/**
 * php准备过程
 * Created by wangjian on 16/10/17.
 */
public class PhpPrepareTask extends Task {

    private static Logger logger = LoggerFactory.getLogger(PhpPrepareTask.class);

    /**
     * 跳板机
     * 用于推送发布包
     */
    private WinitJumpServer jumpServer = null;
    /**
     * 远程终端机,用于校验发布包是否推送成功
     */
    private WinitPhpServer phpServer;
    /**
     * 必传
     */
    private WinitPhpInfo phpInfo;

    /**
     * beetle本机发布
     * @param taskId
     * @param expireTime
     * @param phpInfo
     * @param phpServer
     */
    public PhpPrepareTask(String taskId, Integer expireTime,WinitPhpInfo phpInfo,WinitPhpServer phpServer) {
        super(taskId, expireTime);
        this.phpInfo = phpInfo;
        this.phpServer = phpServer;
    }

    /**
     * 跳板机发布
     * @param taskId
     * @param expireTime
     * @param phpInfo
     * @param phpServer
     * @param jumpServer
     */
    public PhpPrepareTask(String taskId, Integer expireTime,WinitPhpInfo phpInfo,WinitPhpServer phpServer
            ,WinitJumpServer jumpServer) {
        super(taskId, expireTime);
        this.phpInfo = phpInfo;
        this.phpServer = phpServer;
        this.jumpServer = jumpServer;
    }

    @Override
    public TaskStatus call() throws Exception {
        logger.info("com.winit.deploy.task.phpTask.PhpPrepareTask.call start taskId="+this.taskId);
        StringBuffer errorStr = new StringBuffer();

        String dirPath = this.phpInfo.getProjectDirPath();
        String dirName = this.phpInfo.getProjectDirName();
        String serverIp = this.phpInfo.getServerIp();
        String zipTempDir = this.phpInfo.getZipTempDir();
        String zipPath = this.phpInfo.getZipPath();
        String packageName = this.phpInfo.getPackageName();
        String projectName = this.phpInfo.getProjectName();
        String editionNum = this.phpInfo.getEditionNum();
        String backUpDir = this.phpInfo.getBackUpDir();


        //2.校验硬盘是否存在空间
        try {
            String percent = this.phpServer.getPercentOfSpace();
            if("100".equals(percent)){
                errorStr.append("<br>终端空间已满,请先清理后再进行发布!");
            }
        }catch (Exception e){
            errorStr.append("<br>检验终端空间剩余,").append(e.getMessage());
        }
        //3.校验发布包临时目录是否存在
        try {
            this.phpServer.isPathExist(zipTempDir,true,true);
        }catch (Exception e){
            errorStr.append("<br>校验发布包临时存放目录,").append(e.getMessage());
        }
        //4.检验工程发布的目录是否存在
        try {
            this.phpServer.isPathExist(dirPath+"/"+dirName,true,true);
        }catch (Exception e){
            errorStr.append("<br>校验工程发布目录,").append(e.getMessage());
        }
        //5.检出环境配置文件
        try {
            this.deployPrepare();
        }catch (Exception e){
            errorStr.append("<br>校验配置文件,").append(e.getMessage());
        }
        //6.检验工程备份目录是否存在
        if(!this.phpInfo.isVmEnv()){
            try {
                this.phpServer.isPathExist(backUpDir,true,true);
            }catch (Exception e){
                errorStr.append("<br>校验工程备份目录,").append(e.getMessage());
            }
        }
        if(!StringUtils.isEmpty(errorStr.toString())){
            throw new Exception(errorStr.toString());
        }

        //当前task发布使用的发布包存放目录
        String releaseTempPath = zipPath.replace(packageName+".zip","");

        try {
            if(this.jumpServer != null){
                //需要使用跳板机时,先将config包从本地推送到跳板机,然后再从跳板机推送至终端
                this.jumpServer.deldirs(releaseTempPath);
                this.jumpServer.mkdirs(releaseTempPath);
                //推送环境配置文件包至跳板机
                this.pushToJump(releaseTempPath);
                //在跳板机上生成发布发布包
                String editionPath = ProjectUtil.getEditionPath(projectName,editionNum);

                Project project = new Project(projectName,true);
                this.jumpServer.createWarPackage(PackageTypeEnum.PHP,releaseTempPath,editionPath,this.taskId,packageName,"",project.getProjectConfig().getConfigPath());
                //推送php备份脚本
                this.jumpServer.doPush("/home/beetle/shell/beetle_php_bak.sh","/home/beetle/",serverIp,this.phpInfo.getSshPort());
                //推送war包至终端机
                this.jumpServer.doPush(zipPath,zipTempDir+"/"+packageName+".zip",serverIp,this.phpInfo.getSshPort());
            }else{
                this.doPush();
            }
            this.phpServer.doCheckPackage();

        }catch (Exception e){
            throw e;
        }finally {
        }

        logger.info("com.winit.deploy.task.phpTask.PhpPrepareTask.call end taskId="+this.taskId);
        return TaskStatus.STATUS_SUCCESS;
    }

    //检出环境配置文件
    private boolean deployPrepare() throws Exception{
        String projectName = this.phpInfo.getProjectName();
        String editionNum = this.phpInfo.getEditionNum();
        String configPath = this.phpInfo.getConfigPath();
        String packageName = this.phpInfo.getPackageName();

        Project project = new Project(projectName,true);
        ProjectSetConfig setConfig = project.getProjectSetConfig();
        String configProjectName = setConfig.getConfigProjectName();

        StringBuffer configSvnURL = new StringBuffer();
        configSvnURL.append(ConfigUtil.getValue("env_config_check_svn_path")).append(configPath).append("/").append(configProjectName);

        String toPath = ProjectUtil.getProjectFilePath(projectName)+editionNum+"/release";
        ProjectUtil.checkOutConfigFile(configSvnURL.toString(),toPath,taskId);
        //校验配置文件
        String php_config_validata = ConfigUtil.getValue("php_config_validata");
        if(!StringUtils.isEmpty(php_config_validata)
                && "true".equals(php_config_validata)
                && !this.phpInfo.isVmEnv()){
            String baseConfigPath = project.getProjectCode().getCodePath();
            try {
                ProjectUtil.checkConfigFile(toPath+"/"+taskId,baseConfigPath);
            }catch (Exception e){
                logger.error("com.winit.deploy.task.phpTask.PhpPrepareTask.deployPrepare校验配置文件异常。",e);
                throw e;
            }
        }

        //本地发布,生成发布包
        if(this.jumpServer == null){
            String zipPath = ProjectUtil.getProjectFilePath(projectName)+editionNum+"/target/"
                    +"/"+packageName+".zip";
            ProjectUtil.replaceConfigFile(PackageTypeEnum.PHP,toPath+"/"+this.taskId,this.phpInfo.getZipPath().replace(packageName+".zip","")
                    ,zipPath,packageName,project.getProjectConfig().getConfigPath(),this.phpInfo.isVmEnv());
        }
        return true;
    }

    /**
     * 从beetle本机推送
     * @return
     * @throws Exception
     */
    private void doPush() throws Exception{
        //1.推送php备份脚本
        String[] pa = new String[7];
        pa[0] = "scp";
        pa[1] = "-i";
        pa[2] = this.phpInfo.getKeyFilePath();
        pa[3] = "-P";
        pa[4] = this.phpInfo.getSshPort();
        pa[5] = Constants.SHELL_PATH+"shell/init/beetle_php_bak.sh";
        pa[6] = this.phpInfo.getUserName()+"@"+this.phpInfo.getServerIp()+":/home/"+this.phpInfo.getUserName()+"/";
        String str = ShellRunUtil.runShell(pa);
        logger.info("PhpPrepareTask:从beetle本机推送php备份脚本,返回:"+str);
        if(!StringUtils.isEmpty(str)){
            throw new Exception("PhpPrepareTask:从beetle本机推送php备份脚本失败,"+str);
        }
        //2.推送发布包
        String[] param = new String[7];
        param[0] = "scp";
        param[1] = "-i";
        param[2] = this.phpInfo.getKeyFilePath();
        param[3] = "-P";
        param[4] = this.phpInfo.getSshPort();
        param[5] = this.phpInfo.getZipPath();
        param[6] = this.phpInfo.getUserName()+"@"+this.phpInfo.getServerIp()+":"
                +this.phpInfo.getZipTempDir()+"/"+this.phpInfo.getPackageName()+".zip";
        String rtnStr = ShellRunUtil.runShell(param);
        logger.info("PhpPrepareTask:从beetle本机推送发布包,返回:"+rtnStr);
        if(!StringUtils.isEmpty(rtnStr)){
            throw new Exception("PhpPrepareTask:从beetle本机推送发布包失败,"+rtnStr);
        }
    }

    private void pushToJump(String releaseTempPath) throws Exception{
        String evnConfigTarPath = ProjectUtil.getEditionPath(this.phpInfo.getProjectName(),this.phpInfo.getEditionNum())+
                "/release/"+this.taskId+".tgz";
        String level = this.jumpServer.getLevel();
        if("1".equals(level)){
            this.pushToLevelOneFromLocal(evnConfigTarPath,releaseTempPath,this.jumpServer.getIp()
                    ,String.valueOf(this.jumpServer.getServerPort()));
        }else{
            WinitJumpServer levelOne = LinuxJumpServerFactory.getInstance().getParentServer(this.jumpServer.getIp());
            levelOne.deldirs(releaseTempPath);
            levelOne.mkdirs(releaseTempPath);
            this.pushToLevelOneFromLocal(evnConfigTarPath,releaseTempPath,levelOne.getIp(),String.valueOf(levelOne.getServerPort()));
            levelOne.doPush(releaseTempPath+this.taskId+".tgz",releaseTempPath+"/",this.jumpServer.getIp()
                    , String.valueOf(this.jumpServer.getServerPort()));
        }
    }

    /**
     *将环境配置文件压缩包推送至一级跳板机
     * @param evnConfigTarPath 环境配置文件压缩包路径 在版本目录下
     * @param releaseTempPath 当前task发布包路径存放目录
     * @param ip
     * @param port
     * @throws Exception
     */
    private void pushToLevelOneFromLocal(String evnConfigTarPath,String releaseTempPath,String ip,String port) throws Exception{
        String[] param = new String[7];
        param[0] = "scp";
        param[1] = "-i";
        param[2] = this.phpInfo.getKeyFilePath();
        param[3] = "-P";
        param[4] = port;
        param[5] = evnConfigTarPath;
        param[6] = this.phpInfo.getUserName()+"@"+ip+":"+releaseTempPath;
        String str = ShellRunUtil.runShell(param);
        logger.info("PhpPrepareTask:从beetle本机推送发布包至跳板机,返回:"+str);
        if(!StringUtils.isEmpty(str)){
            throw new Exception("PhpPrepareTask:从beetle本机推送发布包至跳板机失败,"+str);
        }
    }
}
